//////////////////////////////////////////////////////////////////////////////////
//
// ActionScript 3.0 Common Library (MIT License)
// Copyright (c) 2009 AS3CommonCode | Tony Birleffi | http://www.mosaiceye.com
// 
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
// 
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////////

package org.as3commoncode.utils 
{
	/**
	 * This is a utility class with many useful methods for strings.
	 * 
	 * @author Tony Birleffi
	 */
	public class StringUtil 
	{
		/**
		 * Checks to make sure a string has readable characters.
		 * 
		 * @example
		 * <listing>
         * import org.as3commoncode.utils.StringUtil;
         * var isEmpty:Boolean = StringUtil.isEmpty('I like to say Proximity!');
         * // returns false.
         * </listing>
         * 
		 * @param string	string value to check.
		 * @return Boolean.
		 */
		public static function isEmpty(string:String):Boolean
		{
			var len:Number = string.length;
			for (var i:Number = len; i > -1; --i) if(string.charCodeAt(i) > 32) return false;
			return true;
		}
		
		/**
		 * Search & replace all characters specified in the parameters.
		 * 
		 * @example
		 * <listing>
         * import org.as3commoncode.utils.StringUtil;
         * var str:String = StringUtil.replace('I like to say Proximity!', 'like', 'love');
         * // returns "I love to say Proximity!".
         * </listing>
         *
		 * @param string	string value to search.
		 * @param search	the character to search for.
		 * @param replace	the character to replace with.
		 * @return String.
		 */
		public static function replace(string:String, search:String, replace:String):String
		{		
			return string.split(search).join(replace);
		}
		
		/**
		 * Removes all instances of the remove string in the input string.
		 * 
		 * @example
		 * <listing>
         * import org.as3commoncode.utils.StringUtil;
         * var str:String = StringUtil.remove('I like to say Proximity!', ' Proximity');
         * // returns "I like to say!".
         * </listing>
         * 
		 * @param string	string that will be checked for instances of remove string.
		 * @param remove	string that will be removed from the input string.
		 * @return String.
		 */	
		public static function remove(string:String, remove:String):String
		{
			return StringUtil.replace(string, remove, "");
		}
		
		/**
		 * Add/insert a new string at a certain position in the source string.
		 * 
		 * @example
		 * <listing>
         * import org.as3commoncode.utils.StringUtil;
         * var str:String = StringUtil.addAt('I like grapes.', 'red ', 7);
         * // returns "I like red grapes.".
         * </listing>
         * 
		 * @param string	current string to look at.
		 * @param value		string to insert.
		 * @param position	string position.
		 * @return String.
		 */
		public static function addAt(string:String, value:*, position:int):String 
		{
			if (position > string.length) position = string.length;
			var firstPart:String = string.substring(0, position);
			var secondPart:String = string.substring(position, string.length);
			return (firstPart + value + secondPart);
		}
		
		/**
		 * Replaces a part of the text between 2 positions.
		 * 
		 * @example
		 * <listing>
         * import org.as3commoncode.utils.StringUtil;
         * var str:String = StringUtil.replaceAt('I like grapes.', 'love ', 3, 6);
         * // returns "I love grapes.".
         * </listing>
         * 
		 * @param string		current string to look at.
		 * @param value			string to replace with.
		 * @param beginIndex	beginning index.
		 * @param endIndex		ending index.
		 * @return String.
		 */
		public static function replaceAt(string:String, value:*, beginIndex:int, endIndex:int):String 
		{
			beginIndex = Math.max(beginIndex, 0);
			endIndex = Math.min(endIndex, string.length);
			var firstPart:String = string.substr(0, beginIndex);
			var secondPart:String = string.substr(endIndex, string.length);
			return (firstPart + value + secondPart);
		}
		
		/**
		 * Removes a part of the text between 2 positions.
		 * 
		 * @example
		 * <listing>
         * import org.as3commoncode.utils.StringUtil;
         * var str:String = StringUtil.removeAt('I like grapes.', 'love ', 7, 13);
         * // returns "I like.".
         * </listing>
         * 
		 * @param string		current string to look at.
		 * @param beginIndex	beginning index.
		 * @param endIndex		ending index.
		 * @return String.
		 */
		public static function removeAt(string:String, beginIndex:int, endIndex:int):String 
		{
			return StringUtil.replaceAt(string, "", beginIndex, endIndex);
		}
		
		/**
		 * Reverse each character in a string.
		 * 
		 * @example
		 * <listing>
         * import org.as3commoncode.utils.StringUtil;
         * var str:String = StringUtil.reverseChars('stop');
         * // returns "pots".
         * </listing>
         * 
		 * @param string	string that will have its characters reversed.
		 * @return String.
		 */
		public static function reverseChars(string:String):String
		{
			var va:Array = string.split("");
			va.reverse();
			var str:String = va.join("");
			return remove(str, ","); 
		}
		
		/**
		 * Reverse the words in a string.
		 * 
		 * @example
		 * <listing>
         * import org.as3commoncode.utils.StringUtil;
         * var str:String = StringUtil.reverseWords('The end of the world is near.');
         * // returns ".near is world the of end The".
         * </listing>
         * 
		 * @param string	string that will have its words reversed.
		 * @return String.
		 */
		public static function reverseWords(string:String):String
		{
			var va:Array = string.split(" ");
			va.reverse();
			var str:String = va.join(" ");
			return replace(str, ",", " ");
		}
		
		/**
		 * Converts a string that is longer than the max charcters parameter, 
		 * shorten it & returns the string with elipses "...".
		 * 
		 * @example
		 * <listing>
         * import org.as3commoncode.utils.StringUtil;
         * var str:String = StringUtil.elipse('The end of the world is near.', 7);
         * // returns "The end...".
         * </listing>
         * 
		 * @param string	string value to alter.
		 * @param max		maximum amount of characters.
		 * @return String.
		 */
		public static function elipse(string:String, max:Number):String
		{
			var tmpString:String;
			if(string.length > max)
			{
				tmpString = string.slice(0, max - 3) + "...";
				return tmpString;
			}
			return string;
		}
		
		/**
		 * Converts the first character in a string to Uppercase.
		 * 
		 * @example
		 * <listing>
         * import org.as3commoncode.utils.StringUtil;
         * var str:String = StringUtil.firstToUpper('how');
         * // returns "How".
         * </listing>
         * 
		 * @param string	string value to alter.
		 * @return String.
		 */
		public static function firstToUpper(string:String):String
		{
			return string.substr(0, 1).toUpperCase() + string.substr(1);
		}
		
		/**
		 * Convert the first letter of each word in a string to Uppercase.
		 * 
		 * @example
		 * <listing>
         * import org.as3commoncode.utils.StringUtil;
         * var str:String = StringUtil.toTitleCase('how are you doing?');
         * // returns "How Are You Doing?".
         * </listing>
         * 
		 * @param string	string value to alter.
		 * @return String.
		 */
		public static function toTitleCase(string:String):String
		{
			var tmp_array:Array = string.split(" ");
			for(var it:String in tmp_array) tmp_array[ it ] = StringUtil.firstToUpper(tmp_array[ it ]);
			return tmp_array.join(" ");
		}
		
		/**
		 * Compares 2 strings for equality, if "caseSensitive" is not specified 
		 * compares the strings based on lower case.
		 * 
		 * @example
		 * <listing>
         * import org.as3commoncode.utils.StringUtil;
         * var ifEqualStrings:Boolean = StringUtil.stringsAreEqual('BONFIRE', 'bonfire', true);
         * // returns false.
         * </listing>
         * 
		 * @param firstString		first string.
		 * @param secondString		second string
		 * @param caseSensitive		whether to look at both strings case, defaults to false.
		 * @return Boolean.
		 */
		public static function stringsAreEqual(firstString:String, secondString:String, caseSensitive:Boolean = false):Boolean
		{
			if(caseSensitive) return (firstString == secondString);
			else return (firstString.toLowerCase() == secondString.toLowerCase());
		}
		
		/**
		 * Rips through a string looking for a single containing characters.
		 * 
		 * @example
		 * <listing>
         * import org.as3commoncode.utils.StringUtil;
         * var ifCharExist:Boolean = StringUtil.containsChar('Proximity rules!!', 'r');
         * // returns true.
         * </listing>
         * 
		 * @param string	string to search.
		 * @param chars		character to compare.
		 * @return Boolean.
		 */
		public static function containsChar(string:String, chars:String):Boolean
		{
			var len:Number = chars.length - 1;
			for (var i:Number = len; i >= 0 ; i--) if (string.indexOf(chars.charAt(i)) >= 0) return true;
			return false;
		}
		
		/**
		 * Rips through a string looking for a containing word.
		 * 
		 * @example
		 * <listing>
         * import org.as3commoncode.utils.StringUtil;
         * var ifWordExist:Boolean = StringUtil.containsWord('Proximity rules!!', 'rules', false);
         * // returns true.
         * </listing>
         * 
		 * @param string			string to search.
		 * @param word				character to compare.
		 * @param caseSensitive		whether to look at both strings case, defaults to false.
		 * @return Boolean.
		 */
		public static function containsWord(string:String, word:String, caseSensitive:Boolean = false):Boolean
		{
			var da:Array = string.split(" ");
			var len:Number = da.length - 1;
			
			for (var i:Number = len; i >= 0 ; i--)
			{
				var str:String = da[ i ];
				if(StringUtil.stringsAreEqual(str, word, caseSensitive) == true) return true;
			}
			
			return false;
		}
	
		/**
	 	 * Determines whether the specified string begins with the specified prefix.
		 * 
		 * @example
		 * <listing>
         * import org.as3commoncode.utils.StringUtil;
         * var ifBeginsWith:Boolean = StringUtil.beginsWith('begins with', 'c');
         * // returns false.
         * </listing>
         * 
		 * @param string	string that the prefix will be checked against.
		 * @param prefix	prefix that will be tested against the string.
		 * @return Boolean.
		 */	
		public static function beginsWith(string:String, prefix:String):Boolean
		{			
			return (prefix == string.substring(0, prefix.length));
		}
		
		/**
	 	 * Determines whether the specified string ends with the specified suffix.
		 * 
		 * <listing>
         * import org.as3commoncode.utils.StringUtil;
         * var ifEndsWith:Boolean = StringUtil.endsWith('the end', 'end');
         * // returns true.
         * </listing>
         * 
		 * @param string	string that the suffix will be checked against.
		 * @param suffix	suffix that will be tested against the string.
		 * @return Boolean.
		 */	
		public static function endsWith(string:String, suffix:String):Boolean
		{			
			return (suffix == string.substring(string.length, (string.length - suffix.length)));
		}
		
		/**
		 * Removes whitespace from the front and the end of the specified string.
		 * 
		 * @example
		 * <listing>
         * import org.as3commoncode.utils.StringUtil;
         * var str:String = StringUtil.trim(' abcde ');
         * // returns "abcde".
         * </listing>
         * 
		 * @param string	string whose beginning and ending whitespace will be removed.
		 * @return String.
		 */			
		public static function trim(string:String):String
		{
			return StringUtil.leftTrim(StringUtil.rightTrim(string));
		}
	
		/**
		 * Removes whitespace from the front of the specified string.
		 * 
		 * @example
		 * <listing>
         * import org.as3commoncode.utils.StringUtil;
         * var str:String = StringUtil.leftTrim(' abcde');
         * // returns "abcde".
         * </listing>
         * 
		 * @param string	string whose beginning whitespace will will be removed.
		 * @return String.
		 */	
		public static function leftTrim(string:String):String
		{
			var size:Number = string.length;
			for(var i:Number = 0; i < size; i++) if(string.charCodeAt(i) > 32) return string.substring(i);
			return "";
		}
	
		/**
		 * Removes whitespace from the end of the specified string.
		 * 
		 * @example
		 * <listing>
         * import org.as3commoncode.utils.StringUtil;
         * var str:String = StringUtil.rightTrim('abcde ');
         * // returns "abcde".
         * </listing>
         * 
		 * @param string	string whose ending whitespace will will be removed.
		 * @return String.
		 */	
		public static function rightTrim(string:String):String
		{
			var size:Number = string.length;
			for(var i:Number = size; i > 0; i--) if(string.charCodeAt(i - 1) > 32) return string.substring(0, i);
			return "";
		}
		
		/**
		 * Removes the first and last characters in a string.
		 * 
		 * @example
		 * <listing>
         * import org.as3commoncode.utils.StringUtil;
         * var str:String = StringUtil.trimCharacters('abcde');
         * // returns "bcd".
         * </listing>
         * 
		 * @param string	string to modify.
		 * @return String.
		 */
		public static function trimCharacters(string:String):String
		{
			return StringUtil.leftTrimCharacter(StringUtil.rightTrimCharacter(string));
		}
		
		/**
		 * Removes the first character in the string.
		 * 
		 * @example
		 * <listing>
         * import org.as3commoncode.utils.StringUtil;
         * var str:String = StringUtil.leftTrimCharacter('abcde');
         * // returns "a".
         * </listing>
         * 
		 * @param string	string to modify.
		 * @return String.
		 */
		public static function leftTrimCharacter(string:String):String
		{
			var size:Number = string.length;
			return string.substr(1, size);
		}
		
		/**
		 * Removes the last character in the string.
		 * 
		 * @example
		 * <listing>
         * import org.as3commoncode.utils.StringUtil;
         * var str:String = StringUtil.rightTrimCharacter('abcde');
         * // returns "e".
         * </listing>
		 * 
		 * @param string	string to modify.
		 * @return String.
		 */
		public static function rightTrimCharacter(string:String):String
		{
			var size:Number = string.length;
			return string.substr(0, size - 1);
		}
		
		/**
		 * Remove the file extension from a string and sends back the name.
		 * 
		 * @example
		 * <listing>
         * import org.as3commoncode.utils.StringUtil;
         * var str:String = StringUtil.extractExtension('file.jpg');
         * // returns "file".
         * </listing>
         * 
		 * @param vFileName		file name to remove the extension from.
		 * @return String.
		 */
		public static function removeExtension(vFileName:String):String
		{
			var extensionIndex:Number = vFileName.lastIndexOf('.');
			if (extensionIndex == -1) return vFileName;
			else return vFileName.substr(0, extensionIndex);
		}
		
		/**
		 * Removes the filename and sends back the extension.
		 * 
		 * @example
		 * <listing>
         * import org.as3commoncode.utils.StringUtil;
         * var str:String = StringUtil.extractExtension('file.jpg');
         * // returns ".jpg".
         * </listing>
         * 
		 * @param fileName	file name to extract the extension from.
		 * @return String.
		 */
		public static function extractExtension(fileName:String):String
		{
			var extensionIndex:Number = fileName.lastIndexOf('.');
			if (extensionIndex == -1) return "";
			else return fileName.substr(extensionIndex + 1, fileName.length);
		}
		
		/**
		 * Search for the first letter in the data array passed.
		 * 
		 * @example
		 * <listing>
         * import org.as3commoncode.utils.StringUtil;
         * var arr:Array = StringUtil.searchFirstLetter('a', [ apple, peach, orange, appricot ]);
         * // returns "apple, apricot".
         * </listing>
         * 
		 * @param input 		pass in string to search for.
		 * @param arrayData		pass in data array to search through.
		 * @return Array.
		 */
		public static function searchFirstLetter(input:String, arrayData:Array):Array
		{
			// Set the index array to return.
			var indexCol:Array = [];
			
			// Define values.
			var temparray:Array = [];
			var holder:String;
			var len:Number = arrayData.length;
			
			// Convert input to lower case always.
			input = input.toLowerCase();
		
			// Go through search array.
			for (var i:Number = 0; i<len; ++i) 
			{
				// Define the string to search.
				holder = new String(arrayData[i]);
				
				// Convert to a new string all lower case.
				var tstr:String = holder.toLowerCase();
				
				// Split the string into an array.
				temparray = tstr.split("");
				
				// Check to see if the first letter matches and push into an array.
				if(temparray[ 0 ] == input) indexCol.push(i);
			}
			
			// Return the index array collection.
			return indexCol;
		}
		
		/**
		 * Fixes double newlines in a string.
		 * 
		 * @example
		 * <listing>
         * import org.as3commoncode.utils.StringUtil;
         * var arr:Array = StringUtil.fixNewLines('The tree./r');
         * // returns "The tree".
         * </listing>
         *
		 * @param input		value.
		 * @return String.
		 */
		public static function fixNewLines(input:String):String 
		{
			return input.replace(/\r\n/gm, "\n");
		}
		
		/**
		 * Parse the number.
		 * 
		 * @example
		 * <listing>
         * import org.as3commoncode.utils.StringUtil;
         * var arr:Array = StringUtil.parseNumber('100000');
         * // returns "100,000".
         * </listing>
         * 
		 * @param value		String.
		 * @return String.
		 */
		public static function parseNumber(value:String):String
		{
			var connections:String = "";
			if(value.length == 4) 
			{
				var thousandsEdit:String = StringUtil.addCommaAt(value, 1);
				connections = thousandsEdit;
			} 
			else if (value.length == 5) 
			{
				var thousandsEdit2:String = StringUtil.addCommaAt(value, 2);
				connections = thousandsEdit2;
			} 
			else if (value.length == 6) 
			{
				var hundredThousandsEdit:String = StringUtil.addCommaAt(value, 3);
				connections = hundredThousandsEdit;
			} 
			else if (value.length == 7) 
			{
				var millionsEdit1:String = StringUtil.addCommaAt(value, 1);
				var millionsEdit2:String = StringUtil.addCommaAt(millionsEdit1, 5);
				connections = millionsEdit2;
			} 
			else connections = value;
			return connections;
		}
		
		 public static function parseStyleNumberString(s:String):Number {
        		
	        	var num:Number;
        	
	        	// Figure.
	        	var str:String = StringUtil.trim(s);
	        	var colorByPound:Boolean = StringUtil.beginsWith(str, "#");
	        	var colorByZeroX:Boolean = StringUtil.beginsWith(str, "0x");
	        	var decimal:Boolean = StringUtil.beginsWith(str, ".");
	        	var zeroDecimal:Boolean = StringUtil.beginsWith(str, "0.");
	        	var pxEnd:Boolean = StringUtil.endsWith(str, 'px');
	        	
	        	// Color's with the # syntax.
	        	if(colorByPound) num = Number('0x' + StringUtil.leftTrimCharacter(str));
	        	
	        	// Color's with the 0x syntax.
	        	if(colorByZeroX) num = Number(str);
	        	
	        	// If the string ends with 'px'.
	        	if(pxEnd) num = Number(StringUtil.remove(str, 'px'));
	        	
	        	// If it begins with a decimal or zero and then a decimal.
	        	if(decimal || zeroDecimal) num = Number(str);
	        	
	        	return num;
        	
        }
		
		/**
		 * Method to add a comma at.
		 * 
		 * @example
		 * <listing>
         * import org.as3commoncode.utils.StringUtil;
         * var arr:Array = StringUtil.addCommaAt('100000', 3);
         * // returns "100,000".
         * </listing>
         * 
		 * @param value			String.
		 * @param position		int.
		 */
		public static function addCommaAt(value:String, position:int):String
		{
			if(position > value.length) position = value.length;
			var firstPart:String = value.substring(0, position);
			var secondPart:String = value.substring(position, value.length);
			return (firstPart + "," + secondPart);
		}
	}
}
